package com.tkwayne.ftpclient.client;

import com.tkwayne.ftpclient.core.FTPClientPool;
import com.tkwayne.ftpclient.util.ByteUtil;
import com.tkwayne.ftpclient.util.FtpConstant;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * FTPClientHelper
 * @author wayne
 * @description 
 * @date 2019/7/20 16:39
 */
public class FTPClientHelper {

	private static Logger logger = LoggerFactory.getLogger(FTPClientHelper.class);

	private FTPClientPool ftpClientPool;

	public FTPClientPool getFtpClientPool() {
		return ftpClientPool;
	}

	public void setFtpClientPool(FTPClientPool ftpClientPool) {
		this.ftpClientPool = ftpClientPool;
	}

	/**
	  * 下载文件到指定目录
	  * @author wayne
	  * @date  2019/7/24 13:24
	  * @param pathName FTP服务器文件地址 /upload/default/2019-07/31/image/1564549614000_5511.png
	  * @param localPath 下载后的文件路径 D:/downLoad/image
	  * @param localFileName 下载后的文件名称 testFile
	  * @return
	  */
	public boolean downloadFile(String pathName, String localPath,String localFileName) throws Exception{

		logger.info("start downLoad pathName: {}, localPath:{} , localFileName:{}",pathName,localPath,localFileName);

		boolean flag = false;

		OutputStream os= null;
		FTPClient ftpClient = null;

		try {

			ftpClient = ftpClientPool.borrowObject();

			File localFile = new File(localPath);

			if (!localFile.isDirectory()) {
				localFile.mkdirs();
			}

			String suffix = pathName.substring(pathName.lastIndexOf(".") + 1);

			os = new FileOutputStream(localFile+File.separator+localFileName+"."+suffix);

			flag = ftpClient.retrieveFile(pathName, os);

		} catch (Exception e){
			logger.error("downloadFile fail pathName : ["+pathName+" ] ,localPath : [ "+ localPath+" ]",e);
			throw e;
		}finally {
			if(os != null){
				os.flush();
				os.close();
			}
			if(ftpClient != null) {
				ftpClientPool.returnObject(ftpClient);
			}
		}
		return flag;
	}

	/**
	 * 下载pathName文件
	 * @param pathName FTP服务器文件地址 /upload/default/2019-07/31/image/1564549614000_5511.png
	 * @return 字节数据
	 * @throws Exception
	 */
	public byte[] downloadFileIntoByte(String pathName) throws Exception {

		logger.info("downloadFileIntoByte start pathName: {}",pathName);

		FTPClient ftpClient = null;
		InputStream in = null;
		try {

			ftpClient = ftpClientPool.borrowObject();

			in = ftpClient.retrieveFileStream(new String(pathName.getBytes(FtpConstant.GBK),FtpConstant.ISO_8859_1));

			return ByteUtil.inputStreamToByteArray(in);

		}catch (Exception e){
			logger.error("start downloadFileIntoByte pathName : ["+pathName+" ]",e);
			throw e;
		}finally{
			if (in != null) {
				in.close();
			}
			if(ftpClient != null) {
				//completePendingCommand() 方法需要用在返回流的接口内，而且需要在流关闭关闭之后调用
				//此接口内completePendingCommand()会一直在等FTP Server返回226[Transfer complete],
				//但是FTP Server只有在接受到InputStream执行close方法时，才会返回。所以先要执行in.close()
				ftpClient.completePendingCommand();
				ftpClientPool.returnObject(ftpClient);
			}
		}
	}

	/**
	 * 删除目录
	 * @param pathName
	 * @return
	 * @throws IOException
	 */
	public boolean deleteDirectory(String pathName) throws Exception {
		FTPClient client = null;
		try {
			client = ftpClientPool.borrowObject();
			return client.removeDirectory(pathName);
		} catch (Exception e) {
			logger.error("deleteDirectory file fail pathName : [ "+ pathName+" ]",e);
			throw e;
		} finally {
			ftpClientPool.returnObject(client);
		}
	}
	
	/**
	 * 删除文件
	 * @param fileName
	 * @return
	 * @throws Exception
	 */
	public boolean deleteFile(String fileName) throws Exception {
		FTPClient client = null;
		try {
			client = ftpClientPool.borrowObject();
			return client.deleteFile(fileName);
		} catch (Exception e) {
			logger.error("remove file fail fileName : [ "+ fileName+" ]",e);
			throw e;
		} finally {
			ftpClientPool.returnObject(client);
		}
	}
	
	/**
	 * 上传文件 
	 * @param file xxx.png || xxx.jpg
	 * @param targetPath 文件存储路径
	 * @param newFileName 新文件名称
	 * @return true | false
	 * @throws Exception
	 */
	public boolean storeFile(String file, String targetPath, String newFileName) throws Exception {

		logger.info("file : [ "+file+" ] targetPath: [ "+targetPath + " ] , newFileName: ["+newFileName+" ]");

		FTPClient ftpClient = null;

		FileInputStream input = null;
		try {

			ftpClient = ftpClientPool.borrowObject();

			createDirectory(ftpClient,targetPath);

			input = new FileInputStream(new File(file));

			return ftpClient.storeFile(newFileName, input);

		} catch (Exception e) {
			logger.error("file : [ "+file+" ] targetPath: [ "+targetPath + " ] , newFileName: ["+newFileName+" ]",e);
			throw e;
		} finally {
			if(input != null){
				input.close();
			}
			if(ftpClient != null) {
				//还原当前client的指向位置
				ftpClient.changeWorkingDirectory("/");
				ftpClientPool.returnObject(ftpClient);
			}
		}
	}

	/**
	 * 上传文件
	 * @param input 源文件输入流
	 * @param targetPath 文件存储路径
	 * @param newFileName 新文件名称
	 * @return true | false
	 * @throws Exception
	 */
	public boolean storeFile(InputStream input, String targetPath, String newFileName) throws Exception {

		logger.info("targetPath: [ "+targetPath + " ] , newFileName: ["+newFileName+" ]");

		FTPClient ftpClient = null;

		try {

			ftpClient = ftpClientPool.borrowObject();

			createDirectory(ftpClient,targetPath);

			return ftpClient.storeFile(newFileName, input);

		} catch (Exception e) {
			logger.error("targetPath: [ "+targetPath + " ] , newFileName: ["+newFileName+" ]",e);
			throw e;
		} finally {
			if(input != null){
				input.close();
			}
			if(ftpClient != null) {
				//还原当前client的指向位置
				ftpClient.changeWorkingDirectory("/");
				ftpClientPool.returnObject(ftpClient);
			}
		}
	}

	/**
	  * 递归创建目录
	  * @author wayne
	  * @date  2019/7/23 13:10
	  * @param 
	  * @return 
	  */
	private static void createDirectory(FTPClient ftpClient,String filePath) throws Exception {
		String directory = filePath + "/";
		// 如果远程目录不存在，则递归创建远程服务器目录
		if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(ftpClient,directory,filePath)) {
			int start = directory.startsWith("/") ? 1 : 0;
			int end = directory.indexOf("/", start);
			StringBuilder path = new StringBuilder();
			while (true) {
				String subDirectory = new String(filePath.substring(start, end).getBytes(FtpConstant.GBK), FtpConstant.ISO_8859_1);
				path.append("/").append(subDirectory);
				if (!existFile(ftpClient,path.toString())) {
					if (makeDirectory(ftpClient,subDirectory)) {
						changeWorkingDirectory(ftpClient,subDirectory,filePath);
					} else {
						changeWorkingDirectory(ftpClient,subDirectory,filePath);
					}
				} else {
					logger.info("FTP existFile [ " + path + " ]");
					changeWorkingDirectory(ftpClient,subDirectory,filePath);
				}
				start = end + 1;
				end = directory.indexOf("/", start);
				// 检查所有目录是否创建完毕
				if (end <= start) {
					break;
				}
			}
		}
	}

	/**
	  * 改变远程服务器目录
	  * @author wayne
	  * @date  2019/7/23 13:11
	  * @param
	  * @return
	  */
	private static boolean changeWorkingDirectory(FTPClient ftpClient,String directory,String path) {

		boolean flag = true;
		try {
			String[] rt=ftpClient.doCommandAsStrings("pwd","");
			Pattern p=Pattern.compile("\"(.*?)\"");
			Matcher m=p.matcher(rt[0]);
			String locationPath = "";
			if(m.find()){
				locationPath = m.group(0).replace("\"","");
			}
			//判断当前所在路径和目标路径是否相同，如果相同则不继续进入
			if(!"".equals(locationPath) && !locationPath.equals("/"+path)){
				flag = ftpClient.changeWorkingDirectory(directory);
				if (flag) {
					logger.info("FTP into [ " + directory + " ] success!");
				} else {
					logger.warn("FTP into [ " + directory + " ] fail!");
				}
			}else{
				logger.warn("FTP into [ " + directory + " ] fail!");
				return false;
			}
		} catch (Exception e) {
			logger.error("changeWorkingDirectory error",e);
		}
		return flag;
	}

	/**
	  * 判断ftp服务器文件是否存在
	  * @author wayne
	  * @date  2019/7/23 13:14
	  * @param
	  * @return
	  */
	private static boolean existFile(FTPClient ftpClient,String path) throws Exception {

		FTPFile[] ftpFileArr = ftpClient.listFiles(path);
		return ftpFileArr != null && ftpFileArr.length > 0;

	}

	// 创建目录
	private static boolean makeDirectory(FTPClient ftpClient,String dir) {
		boolean flag = true;
		try {
			flag = ftpClient.makeDirectory(dir);
			if (flag) {
				logger.info("create [ " + dir + " ] success!");
			} else {
				logger.warn("create [ " + dir + " [ fail!");
			}
		} catch (Exception e) {
			logger.error("makeDirectory error!",e);
		}
		return flag;
	}
   
}
